#include "debugger.h"

//#include "../"

//int main(void)
//{
//	Memory *memory = new_memory();
//	RegisterSet *registerset = new_registerset();
//	Cpu *new_cpu(memory, registerset);
//	Update();
//	promptCommand();
//}


Debugger *new_debugger(Cpu *cpu, Controller *controller, Memory *memory)
{
	Debugger *debugger = (Debugger *) malloc(sizeof(Debugger));
	debugger->memory = memory;
	debugger->cpu = cpu;
	debugger->controller = controller;
	debugger->mem_start = 0;
	return debugger;
}

void debugger_main_loop(Debugger *debugger)
{
	Bit exit_bit = 0;
	int command = 0;

	while(exit_bit == 0)
	{
		debugger_update(debugger);
		command = debugger_prompt_command(debugger);

		if (command == 0)
		{
			printf("command was 0");
			debugger_run_program(debugger);
		} else if (command == 1)
			debugger_load_program(debugger);
		else if (command == 2)
			debugger_run_program(debugger);
		else if (command == 3)
			debugger_clear_memory_block(debugger);
		else if (command == 4)
			debugger_show_mem(debugger);
		else if (command == 5)
			exit_bit = 1;
		else {
			printf("\nInvalid Command\n");
		}
	}
}

//Load Program this will prompt for a filename
void debugger_load_program(Debugger *debugger){
	char filename[FILENAME_MAX];
	int fields;
	FILE *file;
	Register write_address = 0;
	Register value;
	Register *val_ptr = &value;

	printf("Enter the name of the program file:");

	fields = scanf("%s, filename", filename);
	if (fields < 1)
	{
		printf("Error getting file name.\n");
		return;
	}

	file = fopen(filename, "r");
	if (file == NULL)
	{
		printf("Error opening file for reading.\n");
		return;
	}

	while (fscanf(file, "%4hx\n", val_ptr) > 0)
	{
		memory_set_memory_address_register(debugger->memory, write_address++);
		memory_set_memory_data_register(debugger->memory, value);
		memory_perform_write(debugger->memory);
	}
	debugger->cpu->stop_bit = 0;

	fclose(file);

	printf("Read %d instructions into memory.\n", write_address);

	cpu_set_pc(debugger->cpu, 0);
}
//Run Program runs the next step of the program.
void debugger_run_program(Debugger *debugger){
	//in a loop that terminates at the end of the code
	//	execute the next line of code
	//	prompt for continue
	cpu_perform_instruction(debugger->cpu);

}

//Clear Memory Block
void debugger_clear_memory_block(Debugger *debugger){
	int temp1 = 0;
	int temp2 = 0;
	int *mem_loc1 = &temp1;
	int *mem_loc2 = &temp2;
	printf("\n\nEnter memory location to begin clearing at (inclusive): ");
	scanf("\n%x", mem_loc1);
	printf("\nEnter memory location to end clearing at (inclusive): ");
	scanf("\n%x", mem_loc2);
	unsigned short i;
	memory_set_memory_data_register(debugger->memory, 0x0000);
	for (i = *mem_loc1; i <= *mem_loc2; i++)
	{
		memory_set_memory_address_register(debugger->memory, i);
		memory_perform_write(debugger->memory);
	}
	printf("\nBlock cleared.\n\n");
}

//refresh the screen
void debugger_update(Debugger *debugger){
	memory_set_memory_address_register(debugger->memory, debugger->mem_start);
	memory_perform_read(debugger->memory);
	printf("                                        Memory\n");
	printf("Registers                               0x%04X:   0x%04X\n", debugger->mem_start, memory_get_memory_data_register(debugger->memory));
	int i = 0;
	for (i = 0; i < 11; i++)
	{

		if (i < 8)
		{

			memory_set_memory_address_register(debugger->memory, debugger->mem_start + i + 1);
			memory_perform_read(debugger->memory);
			printf("R%X   0x%04X                             0x%04X:   0x%04X\n", i, registerset_get_register(debugger->cpu->registerset, i), debugger->mem_start + i + 1, memory_get_memory_data_register(debugger->memory));

		} else if (i < 10) {

			memory_set_memory_address_register(debugger->memory, debugger->mem_start + i + 1);
			memory_perform_read(debugger->memory);
			printf("                                        0x%04X:   0x%04X\n",  debugger->mem_start + i + 1, memory_get_memory_data_register(debugger->memory));
		} else {
			memory_set_memory_address_register(debugger->memory, debugger->mem_start + i + 1);
			memory_perform_read(debugger->memory);
			printf("Special Registers                       0x%04X:   0x%04X\n",  debugger->mem_start + i + 1, memory_get_memory_data_register(debugger->memory));
		}
	}
	memory_set_memory_address_register(debugger->memory, debugger->mem_start + i + 1);
	memory_perform_read(debugger->memory);
	printf("PC:  0x%04X    IR:  0x%04X              0x%04X:   0x%04X\n",  cpu_get_pc(debugger->cpu), cpu_get_ir(debugger->cpu), debugger->mem_start + i + 1, memory_get_memory_data_register(debugger->memory));
	i++;
	memory_set_memory_address_register(debugger->memory, debugger->mem_start + i + 1);
	memory_perform_read(debugger->memory);
	printf("MAR: 0x%04X    MDR: 0x%04X              0x%04X:   0x%04X\n", debugger->memory->mar,  memory_get_memory_data_register(debugger->memory), debugger->mem_start + i + 1, memory_get_memory_data_register(debugger->memory));
	i++;
	memory_set_memory_address_register(debugger->memory, debugger->mem_start + i + 1);
	memory_perform_read(debugger->memory);
	printf("Status Flags                            0x%04X:   0x%04X\n", debugger->mem_start + i + 1, memory_get_memory_data_register(debugger->memory));
	i++;
	memory_set_memory_address_register(debugger->memory, debugger->mem_start + i + 1);
	memory_perform_read(debugger->memory);


	Register temp = cpu_get_state(debugger->cpu);
	int pos = register_get_bit(&temp, P_BIT_POS);
	int zero = register_get_bit(&temp, Z_BIT_POS);
	int neg = register_get_bit(&temp, N_BIT_POS);
	int overflow = register_get_bit(&temp, O_BIT_POS);
	int carry = register_get_bit(&temp, C_BIT_POS);

	printf("N: %i, Z: %i, P: %i, c: %i, o: %i            0x%04X:   0x%04X\n\n",	neg? 1:0, zero? 1:0, pos? 1:0, carry? 1:0, overflow? 1:0, i + 1, memory_get_memory_data_register(debugger->memory));

//	i++;
//	memory_set_memory_address_register(debugger->memory, debugger->mem_start + i + 1);
//	memory_perform_read(debugger->memory);

	}

//ask the user for a command to run
int debugger_prompt_command(Debugger *debugger){
	int temp = 0;
	printf("1) Load, 2) Run, 3) Clear Mem, 4) Show Mem, 5) Exit\n");
	if(debugger->cpu->stop_bit)
	{
		printf("CPU HALTED\n");
	}
	scanf("%i", &temp);
//	printf("\n%i", status);
	return temp;
}

void debugger_show_mem(Debugger *debugger)
{
	int temp = 0;
	int *mem_loc = &temp;
	printf("\n\nEnter memory location to begin display at: ");
	scanf("\n%x", mem_loc);
	debugger->mem_start = *mem_loc;
}
